Helper.using('py.Figures' , function (ns) {
    ns.Vector = function(params) {
        var group = new Kinetic.Group(),
            line, arrow;

        ns.Figure.call(this, params);

        this.getHead = Helper.abstractMethod();
        this.getTail = Helper.abstractMethod();

        this.setType('Vector');

        this.getX = Helper.abstractMethod();
        this.getY = Helper.abstractMethod();
        this.getLength = function() {
            var x = this.getX(), y = this.getY();
            return Math.sqrt(x*x + y*y);
        };

        this.getPerpendicularVector = function(){

            //(a,b) -->(-b,a)

            var getX = function(){
                //return -(params.head.getY() - params.tail.getY());
                return -(this.getHead().getY() - this.getTail().getY());
            };

            var getY = function(){
                return this.getHead().getX() - this.getTail().getX();
            };

            var getHead = function() {
                return this.getHead();
            };

            var getTail = function() {
                return this.getTail();
            };

            return{
                getX:getX,
                getY:getY,
                getHead:getHead,
                getTail:getTail
            }

        }

        //DaoLA
        this.getAngleFromOx = function(){
            var x = this.getX(),
                y = this.getY(),
                head = this.getHead(),
                tail = this.getTail();

            if (x == 0)
            {
                if (y == 0) return ns.AngleMagnitude.fromDegree(0);
                return head.getY() > tail.getY() ? ns.AngleMagnitude.fromDegree(90) : ns.AngleMagnitude.fromDegree(-90);
            }
            if (x > 0)
            {
                return ns.AngleMagnitude.fromRadian(Math.atan(y / x));
            }
            return ns.AngleMagnitude.fromDegree(180 + Math.atan(y / x) * 180 / Math.PI);
        };

        // visual
//        line = new Kinetic.Line({
////            points : [this.getHead().getPosition().x, this.getHead().getPosition().y,
////                this.getTail().getPosition().x,this.getTail().getPosition().y],
//            stroke: "green",
//            strokeWidth: 2,
//            lineJoin: "round",
//            /*
//             * line segments with a length of 33px
//             * with a gap of 10px
//             */
//            dashArray: [33, 10]
//        });
//
//        group.x = this.getTail().getX();
//        group.y = this.getTail().getY();
//        group.add(line);
//
//        this.visual(group);
//
//        this.update = function (viewPort) {
//            var head = this.getHead(),
//                tail = this.getTail(),
//                p1 = viewPort.getPixelPoint(head.getPosition()),
//                p2 = viewPort.getPixelPoint(tail.getPosition()),
//                points = [p1.x, p1.y , p2.x, p2.y],
//                visual = this.visual();
//
//        }
//
//        this.drawFunc = function (viewPort) {
//            this.update(viewPort);
//            this.layer().draw();
//        }
    };

    ns.Vector2Point = function(params) {
        params = Helper.extend({
            head : null,
            tail : null
        }, params);

        ns.Vector.call(this, params);
        this.setType('Vector2Point');

        this.formed = function() {
            return params.head && params.tail && this.getLength();
        };

        this.getX = function() {
            return params.head.getX() - params.tail.getX();
        };

        this.getY = function() {
            return params.head.getY() - params.tail.getY();
        };

        // override for better performance
        this.getLength = function() {
            return ns.Point.distance(params.head, params.tail);
        };

        this.getHead = function() {
            return params.head;
        };

        this.getTail = function() {
            return params.tail;
        };

        this.setHead = function(head){
            params.head = head;
        };

        this.setTail = function(tail){
            params.tail = tail;
        };
    };


    ns.VectorXY = function(params) {
        params = Helper.extend({
            x : NaN,
            y : NaN
        }, params);

        ns.Vector.call(this,params);
        this.setType('VectorXY');

        this.formed = function () {
            var x = params.x, y =params.y;
            return !isNaN(x) && !isNaN(y) && (x*x + y*y)
        };

        this.getX = function() {
            return params.x;
        };

        this.getY = function() {
            return params.y;
        };

        this.getHead = function() {
            return new py.PointXY({x : 0, y : 0});
        };

        this.getTail = function() {
            return new py.PointXY({x : params.x, y : params.y});
        };
    };


});